﻿using AutoMail.Data;
using AutoMail.Models;
using AutoMail.QuartzJobs.Interfaces;
using AutoMail.QuartzJobs.Jobs;
using AutoMail.Service.Interface;
using AutoMail.Tools;
using Microsoft.EntityFrameworkCore;
using Quartz;

namespace AutoMail.QuartzJobs
{
    public class JobsManager : IJobsManager
    {
        private readonly AutoMailContext _context;
        private readonly IConfiguration _configuration;
        private MailSendConfigUtil _mailSendConfigUtil;

        public JobsManager(AutoMailContext context, IConfiguration configuration)
        {
            _context = context;
            _configuration = configuration;
            _mailSendConfigUtil = new MailSendConfigUtil(_configuration);
        }

        public void RefreshMailSendConfig()
        {
            _mailSendConfigUtil = new MailSendConfigUtil(_configuration);
        }

        public async Task<Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>> CurrentStaffsMailJobs()
        {
            // Get all staffs list
            List<EmailJob> staffEmailJobs = await _context.EmailJob.ToListAsync();
            return CreateJobTiggers(staffEmailJobs);
        }

        private Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>> CreateJobTiggers(List<EmailJob> staffEmailJobs)
        {
            Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>> dic_JobTriggers = new Dictionary<IJobDetail, IReadOnlyCollection<ITrigger>>();
            var mailSendServerInfo = _mailSendConfigUtil.GetMailSendServerInfo();
            var mailSendTimesInfo = _mailSendConfigUtil.GetMailSendTimesInfo();

            if (mailSendServerInfo == null || mailSendTimesInfo == null)
            {
                return null;
            }

            foreach (EmailJob mailJobItem in staffEmailJobs)
            {
                // Made forciably using a prepared html template.
                mailJobItem.EmailBody = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Happy_BirthDay.html");
                // BirthDay Mail Sending
                IJobDetail birthdayMailJob = JobBuilder.Create<BirthdayMailSendJob>()
                        .UsingJobData(BirthdayMailSendJob.PropertyUsername, mailSendServerInfo.UserName)
                        .UsingJobData(BirthdayMailSendJob.PropertyPassword, mailSendServerInfo.Password)
                        .UsingJobData(BirthdayMailSendJob.PropertySmtpHost, mailSendServerInfo.SmtpHost)
                        .UsingJobData(BirthdayMailSendJob.PropertySmtpPort, mailSendServerInfo.SmtpPort)
                        .UsingJobData(BirthdayMailSendJob.PropertyEnableSsl, mailSendServerInfo.EnableSsl)
                        .UsingJobData(BirthdayMailSendJob.PropertyRecipient, mailJobItem.Email)
                        .UsingJobData(BirthdayMailSendJob.PropertyCcRecipient, "")
                        .UsingJobData(BirthdayMailSendJob.PropertyReplyTo, "")
                        .UsingJobData(BirthdayMailSendJob.PropertySender, mailSendServerInfo.From)
                        .UsingJobData(BirthdayMailSendJob.PropertyEncoding, mailSendServerInfo.Encoding)
                        .UsingJobData(BirthdayMailSendJob.PropertyMessage, mailJobItem.EmailBody)
                        .UsingJobData(BirthdayMailSendJob.PropertyStaffName, mailJobItem.StaffName)
                        .WithIdentity($"{mailJobItem.Id}_Job_BirthDay", $"{BirthdayMailSendJob.JobGroup}")
                        .WithDescription(BirthdayMailSendJob.JobBuildDescription)
                        .Build();

                var birthdayMailTriggers = new List<ITrigger>();
                int birthMonth = mailJobItem.BirthDay.Value.Month;
                int birthDay = mailJobItem.BirthDay.Value.Day;
                ITrigger trigger = TriggerBuilder.Create()
                    .WithIdentity($"{mailJobItem.Id}_Trigger_Birthday", $"Birthday_Trigger_Group")
                    .WithCronSchedule($"{mailSendTimesInfo.BirthdayMailSendTime} {birthDay} {birthMonth} ? *", // cron 表达式 秒 分 时 日 月 周 年， 周常为？ 年常为*
                    x => { x.WithMisfireHandlingInstructionFireAndProceed(); })
                    .Build();
                birthdayMailTriggers.Add(trigger);

                // Put into the dictionary
                dic_JobTriggers[birthdayMailJob] = birthdayMailTriggers;

                // Made forciably using a prepared html template.
                mailJobItem.EmailBody = Path.Combine(AppDomain.CurrentDomain.BaseDirectory, "Happy_nth_Anniversary_Template.html");
                // Anniversary Mail Sending
                int pastYears = (int)Math.Ceiling((DateTime.Now - mailJobItem.ComeToCompanyDate).Value.TotalDays / 365);
                IJobDetail anniversaryMailJob = JobBuilder.Create<AnniversaryMailSendJob>()
                        .UsingJobData(AnniversaryMailSendJob.PropertyUsername, mailSendServerInfo.UserName)
                        .UsingJobData(AnniversaryMailSendJob.PropertyPassword, mailSendServerInfo.Password)
                        .UsingJobData(AnniversaryMailSendJob.PropertySmtpHost, mailSendServerInfo.SmtpHost)
                        .UsingJobData(AnniversaryMailSendJob.PropertySmtpPort, mailSendServerInfo.SmtpPort)
                        .UsingJobData(BirthdayMailSendJob.PropertyEnableSsl, mailSendServerInfo.EnableSsl)
                        .UsingJobData(AnniversaryMailSendJob.PropertyRecipient, mailJobItem.Email)
                        .UsingJobData(AnniversaryMailSendJob.PropertyCcRecipient, "")
                        .UsingJobData(AnniversaryMailSendJob.PropertyReplyTo, "")
                        .UsingJobData(AnniversaryMailSendJob.PropertySender, mailSendServerInfo.From)
                        .UsingJobData(AnniversaryMailSendJob.PropertyEncoding, mailSendServerInfo.Encoding)
                        .UsingJobData(AnniversaryMailSendJob.PropertyMessage, mailJobItem.EmailBody)
                        .UsingJobData(AnniversaryMailSendJob.PropertyStaffName, mailJobItem.StaffName)
                        .UsingJobData(AnniversaryMailSendJob.PropertyAnniversaryYears, pastYears.ToString())
                        .WithIdentity($"{mailJobItem.Id}_Job_Anniversary", $"{AnniversaryMailSendJob.JobGroup}")
                        .WithDescription(AnniversaryMailSendJob.JobBuildDescription)
                        .Build();

                var anniversaryMailTriggers = new List<ITrigger>();
                int comeMonth = mailJobItem.ComeToCompanyDate.Value.Month;
                int comeDay = mailJobItem.ComeToCompanyDate.Value.Day;
                ITrigger anniversaryTrigger = TriggerBuilder.Create()
                    .WithIdentity($"{mailJobItem.Id}_Trigger_Anniversary", $"Anniversary_Trigger_Group")
                    .WithCronSchedule($"{mailSendTimesInfo.AnniversaryMailSendTime} {comeDay} {comeMonth} ? *", // cron 表达式 秒 分 时 日 月 周 年， 周常为？ 年常为*
                    x => { x.WithMisfireHandlingInstructionFireAndProceed(); })
                    .Build();

                anniversaryMailTriggers.Add(anniversaryTrigger);
                // Put into the dictionary
                dic_JobTriggers[anniversaryMailJob] = anniversaryMailTriggers;
            }

            return dic_JobTriggers;
        }

        public async Task<IReadOnlyCollection<IJobExecutionContext>> GetCurrentExecutingJobs(IScheduler scheduler)
        {
            return await scheduler.GetCurrentlyExecutingJobs();
        }

        public async Task<IReadOnlyCollection<JobKey>> GetAllScheduledJobs(IScheduler scheduler)
        {
            return await scheduler.GetJobKeys(Quartz.Impl.Matchers.GroupMatcher<JobKey>.AnyGroup());
        }

        public async Task ScheduleNewOrModifyJobs(IScheduler scheduler, List<EmailJob> emailJobs)
        {
            var dic_JobTriggers = CreateJobTiggers(emailJobs);
            if (dic_JobTriggers != null)
            {
                await scheduler.ScheduleJobs(dic_JobTriggers, true); 
            }
        }

        public async Task DeleteJobsOfOneStaff(IScheduler scheduler, EmailJob emailJob)
        {
            var dic_JobTriggers = CreateJobTiggers(new List<EmailJob>() { emailJob });

            foreach (var dic_JobTrigger in dic_JobTriggers)
            {
                if (dic_JobTrigger.Key != null)
                {
                    await scheduler.DeleteJob(dic_JobTrigger.Key.Key);
                }

                if (dic_JobTrigger.Value != null)
                {
                    foreach (var triggerItem in dic_JobTrigger.Value)
                    {
                        await scheduler.UnscheduleJob(triggerItem.Key);
                    }
                } 
            }
        }

        public async Task UpdateAllJobs(IScheduler scheduler)
        {
            var dic_JobTriggers = await CurrentStaffsMailJobs();
            if (dic_JobTriggers != null)
            {
                await scheduler.ScheduleJobs(dic_JobTriggers, replace: true); 
            }
        }
    }
}
